package org.tang.hool.webmvc;

import org.tang.hool.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 用于转换客户端url参数为目标方法实参
 *
 * @author Tang Jiujia
 * @since 2022/5/5
 */
public class HandlerAdapter {

    public boolean support(Object handler) {
        return handler instanceof HandlerMapping;
    }

    /**
     * 转换客户端请求url参数为请求处理方法实参，并调用请求处理方法返回modelAndView
     *
     * @param req     请求报文
     * @param resp    返回报文
     * @param handler 封装了请求url和处理方法的处理器映射
     * @return 处理方法返回结果modeAndView
     * @author Tang Jiujia
     * @since 2022/5/5
     */
    public Object handle(HttpServletRequest req, HttpServletResponse resp, Object handler) throws InvocationTargetException, IllegalAccessException {
        HandlerMapping handlerMapping = (HandlerMapping) handler;
        // 方法形参map，其中value表示参数的顺序
        Map<String, Integer> paramMap = new HashMap<>();
        // 方法参数上的annotation数组
        Method method = handlerMapping.getMethod();
        Annotation[][] pa = method.getParameterAnnotations();
        for (int i = 0; i < pa.length; i++) {
            for (Annotation a : pa[i]) {
                if (a instanceof RequestParam) {
                    String paramName = ((RequestParam) a).value();
                    if ("".equals(paramName.trim())) {
                        Parameter parameter = method.getParameters()[i];
                        paramName = parameter.getName();
                    }
                    paramMap.put(paramName, i);
                }
            }
        }

        // 1.根据客户端请求参数信息和Method上的参数信息进行匹配
        Class<?>[] parameterTypes = method.getParameterTypes(); // 方法参数类别
        for (int i = 0; i < parameterTypes.length; i++) {
            Class<?> type = parameterTypes[i];
            if (type == HttpServletRequest.class
                    || type == HttpServletResponse.class) {
                paramMap.put(type.getName(), i);
            }
        }

        Map<String, String[]> reqParameterMap = req.getParameterMap(); // url参数map，key表示参数名，value为参数值
        Object[] paramValues = new Object[parameterTypes.length]; // 方法实参
        for (Map.Entry<String, String[]> param : reqParameterMap.entrySet()) {
            String value = Arrays.toString(param.getValue())
                    .replaceAll("\\[|\\]", "")
                    .replaceAll("\\s", "");
            if (!paramMap.containsKey(param.getKey())) continue;
            int index = paramMap.get(param.getKey()); // 方法参数index
            paramValues[index] = castStringValue(value, parameterTypes[index]);
        }

        String requestName = HttpServletRequest.class.getName();
        if (paramMap.containsKey(requestName)) {
            Integer reqIndex = paramMap.get(requestName);
            paramValues[reqIndex] = req;
        }
        String responseName = HttpServletResponse.class.getName();
        if (paramMap.containsKey(responseName)) {
            Integer respIndex = paramMap.get(responseName);
            paramValues[respIndex] = resp;
        }

        // 取出handler中的方法,反射调用
        return method.invoke(handlerMapping.getController(), paramValues);
    }

    private Object castStringValue(String value, Class<?> clazz) {
        if (clazz == String.class) {
            return value;
        } else if (clazz == Integer.class) {
            return Integer.valueOf(value);
        } else if (clazz == int.class) {
            return Integer.valueOf(value).intValue();
        }
        return null;
    }
}

